package com.sample.mockito.test;

import junit.framework.Assert;
import org.junit.Test;

import java.util.LinkedList;
import java.util.List;

import static org.mockito.Mockito.*;

/*

http://static.javadoc.io/org.mockito/mockito-core/2.13.0/org/mockito/Mockito.html#stubbing
 */
public class SampleTest01 {

    @Test
    public void sampleTest1(){
        //mock creation
        List mockedList = mock(List.class);
        //using mock object
        mockedList.add("one");
        mockedList.clear();
        //verification
        verify(mockedList).add("one");
        verify(mockedList).clear();
    }

    @Test
    public void sampleTest2(){
        //You can mock concrete classes, not just interfaces
        LinkedList mockedList = mock(LinkedList.class);

        //stubbing
        when(mockedList.get(0)).thenReturn("first");
        when(mockedList.get(1)).thenThrow(new RuntimeException());

        //following prints "first"
        System.out.println(mockedList.get(0));
        //following throws runtime exception
        try {
            System.out.println(mockedList.get(1));
            Assert.fail("The code should not be here");
        }catch (Exception e){
            Assert.assertTrue(e instanceof RuntimeException);
        }

        //following prints "null" because get(999) was not stubbed
        System.out.println(mockedList.get(999));
        //Although it is possible to verify a stubbed invocation, usually it's just redundant
        //If your code cares what get(0) returns, then something else breaks (often even before verify() gets executed).
        //If your code doesn't care what get(0) returns, then it should not be stubbed. Not convinced? See here.
        verify(mockedList, times(1)).get(0);
    }

    @Test
    public void sampleTest3(){
        LinkedList mockedList = mock(LinkedList.class);

        //stubbing using built-in anyInt() argument matcher
        when(mockedList.get(anyInt())).thenReturn("element");

        //following prints "element"
        System.out.println(mockedList.get(999));

        //you can also verify using an argument matcher
        verify(mockedList).get(anyInt());
    }

    @Test
    public void sampleTest4(){
        LinkedList mockedList = mock(LinkedList.class);
        //使用mock
        mockedList.add("once");
        mockedList.add("twice");
        mockedList.add("twice");
        mockedList.add("three times");
        mockedList.add("three times");
        mockedList.add("three times");
        //下面的两个验证函数的验证效果一样，因为verify默认验证的就是times(1)
        verify(mockedList).add("once");
        verify(mockedList, times(1)).add("once");
        //验证具体的执行次数
        verify(mockedList, times(2)).add("twice");
        verify(mockedList, times(3)).add("three times");
        //使用never（） 进行验证，never（）相当于times(0)
        verify(mockedList, never()).add("never happened");
        //使用atLeast()/atMost()来进行验证
        verify(mockedList, atLeastOnce()).add("three times");
        verify(mockedList, atLeast(2)).add("three times");
        verify(mockedList, atMost(5)).add("three times");
    }
}